﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace Sprout.Core.Utils
{
    public class ReflectionHelper
    {
        #region 创建/属性检测

        /// <summary>
        /// 根据 Type 创建实例
        /// </summary>
        /// <param name="type">Type</param>
        /// <returns></returns>
        public static object New(Type type)
        {
            return Activator.CreateInstance(type, true);
        }

        /// <summary>
        /// 根据 Type 创建 IList 实例
        /// </summary>
        /// <param name="itemType">Type</param>
        /// <returns></returns>
        public static IEnumerable NewList(Type itemType)
        {
            Type newListType = typeof(List<>);
            newListType = newListType.MakeGenericType(new Type[] { itemType });
            return Activator.CreateInstance(newListType) as IList;
        }

        /// <summary>
        /// 判断 Type 是否是自定义类型
        /// </summary>
        /// <param name="type">Type</param>
        /// <returns></returns>
        public static bool IsCustomType(Type type)
        {
            return (type != typeof(object) && Type.GetTypeCode(type) == TypeCode.Object);
        }

        /// <summary>
        /// 判断 Type 是否 IList 类型
        /// </summary>
        /// <param name="type">Type</param>
        /// <returns></returns>
        public static bool IsListType(Type type)
        {
            return (type.GetInterface("IList") != null);
        }

        /// <summary>
        /// 判断 Type 是否包含属性
        /// </summary>
        /// <param name="type">Type</param>
        /// <param name="propertyName">属性名称</param>
        /// <returns></returns>
        public static bool IsContainProperty(Type type, string propertyName)
        {
            return type.GetProperty(propertyName) != null;
        }

        /// <summary>
        /// 获得 List&lt;T&gt; 中 T 的类型
        /// </summary>
        /// <param name="propertyInfo">PropertyInfo</param>
        /// <returns></returns>
        public static Type GetListGenericType(PropertyInfo propertyInfo)
        {
            PropertyInfo[] childPropertyList = propertyInfo.PropertyType.GetProperties();
            foreach (PropertyInfo childPropertyInfo in childPropertyList)
            {
                if (childPropertyInfo.Name == "Item") return childPropertyInfo.PropertyType;
            }
            return null;
        }

        /// <summary>
        /// 获取泛型对象的 T 类型
        /// </summary>
        /// <param name="type">Type</param>
        /// <returns></returns>
        public static Type GetGenericType(Type type)
        {
            Type itemType = type.GetGenericArguments()[0];
            return itemType;
        }
        #endregion

        #region 属性列表获取/遍历
        /// <summary>
        /// 获取属性名和属性
        /// </summary>
        /// <param name="type">Type</param>
        /// <returns></returns>
        public static Dictionary<string, PropertyInfo> GetPropertyNameDic(Type type)
        {
            Dictionary<string, PropertyInfo> dic = new Dictionary<string, PropertyInfo>();
            foreach (var property in type.GetProperties())
            {
                dic.Add(property.Name, property);
            }
            return dic;
        }
        /// <summary>
        /// 获取属性名和属性
        /// </summary>
        /// <param name="type">Type</param>
        /// <returns></returns>
        public static HashSet<string> GetPropertyNames(Type type)
        {
            HashSet<string> names = new HashSet<string>();
            foreach (var property in type.GetProperties())
            {
                names.Add(property.Name);
            }
            return names;
        }
        /// <summary>
        /// 属性列表遍历
        /// </summary>
        /// <param name="callback">属性处理函数</param>
        /// <param name="type">Type</param>
        public static void Foreach(Action<PropertyInfo> callback, Type type)
        {
            PropertyInfo[] propertyList = type.GetProperties();
            foreach (PropertyInfo propertyInfo in propertyList)
            {
                callback(propertyInfo);
            }
        }

        /// <summary>
        /// 获取属性名和属性值
        /// </summary>
        /// <param name="entity">实体数据</param>
        /// <returns></returns>
        public static Dictionary<string, object> GetPropertyDic(object entity)
        {
            if (entity == null) return null;

            Dictionary<string, object> resultDic = new Dictionary<string, object>();
            Foreach((PropertyInfo propertyInfo) =>
            {
                resultDic.Add(propertyInfo.Name, propertyInfo.GetValue(entity));
            }, entity.GetType());

            return resultDic;
        }
        #endregion

        #region 原始反射获取设置属性值

        /// <summary>
        /// 获取索引值
        /// </summary>
        /// <param name="entity">实体数据</param>
        /// <param name="indexName">索引器名称</param>
        /// <returns></returns>
        public static object GetPropertyIndexValue(object entity, object indexName)
        {
            var method = entity.GetType().GetMethod("get_Item", new Type[] { indexName.GetType() });
            return method.Invoke(entity, new object[] { indexName });
        }

        /// <summary>
        /// 获取属性值
        /// </summary>
        /// <param name="entity">实体数据</param>
        /// <param name="propertyInfo">PropertyInfo</param>
        /// <returns></returns>
        public static object GetPropertyValue(object entity, PropertyInfo propertyInfo)
        {
            if (propertyInfo == null) return null;
            return propertyInfo.GetValue(entity, null);
        }

        /// <summary>
        /// 获取属性值
        /// </summary>
        /// <param name="entity">实体数据</param>
        /// <param name="propertyName">属性名称</param>
        /// <returns></returns>
        public static object GetPropertyValue(object entity, string propertyName)
        {
            if (entity == null) return null;
            return GetPropertyValue(entity, entity.GetType().GetProperty(propertyName));
        }

        /// <summary>
        /// 设置属性值
        /// </summary>
        /// <param name="entity">实体数据</param>
        /// <param name="propertyValue">要设置的数据</param>
        /// <param name="propertyName">属性名称</param>
        public static void SetPropertyValue(object entity, object propertyValue, string propertyName)
        {
            SetPropertyValue(entity, propertyValue, entity.GetType().GetProperty(propertyName));
        }

        /// <summary>
        /// 设置属性值
        /// </summary>
        /// <param name="entity">实体数据</param>
        /// <param name="propertyValue">要设置的数据</param>
        /// <param name="propertyInfo">PropertyInfo</param>
        /// <returns></returns>
        public static void SetPropertyValue(object entity, object propertyValue, PropertyInfo propertyInfo)
        {
            if (propertyValue == null) return;

            if (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                propertyInfo.SetValue(entity, ObjectChangeTypeHelper.ChangeType(propertyValue, propertyInfo.PropertyType.GetGenericArguments()[0]), null);
            }
            else
            {
                propertyInfo.SetValue(entity, ObjectChangeTypeHelper.ChangeType(propertyValue, propertyInfo.PropertyType), null);
            }
        }
        #endregion
    }
}
